using System.Collections.Generic;
using Lucene.Net.Documents;
using Lucene.Net.Index;
using Lucene.Net.Search;

namespace NopSolutions.NopCommerce.LuceneHelper.Queries
{
    public abstract class BaseQuery<T> where T:class
    {

        private Query _query = null;

        protected BaseQuery(Query query)
        {
            _query = query;
        }

        protected BaseQuery()
        {
        }

        public Query Query
        {
            get { return _query; }
            set { _query = value; }
        }

        public T EnsureQuery()
        {
            if (_query == null)
            {
                _query = new TermQuery(new Term("Const", "1")) as Query;
            }
            return this as T;
        }

        public Query GetQueryFromList(IList<int> list, string key)
        {
            return GetQueryFromList(list, key, BooleanClause.Occur.MUST);
        }

        public Query GetQueryFromList(IList<int> list, string key, BooleanClause.Occur occur)
        {
            return GetQueryFromList(list,
                delegate
                {
                    return key;
                },
                id => id.ToString(), occur);
        }

        public Query GetQueryFromList<TQ>(IList<TQ> list, System.Func<TQ, string> key, System.Func<TQ, string> value)
        {
            return GetQueryFromList(list, key, value, BooleanClause.Occur.MUST);
        }

        public Query GetQueryFromList<TQ>(IList<TQ> list, System.Func<TQ, string> key, System.Func<TQ, string> value, BooleanClause.Occur occur)
        {
            if (list.Count > 1)
            {
                var booleanQuery = new BooleanQuery();
                foreach (var id in list)
                {
                    booleanQuery.Add(TermQuery(key.Invoke(id), value.Invoke(id)), occur);
                }
                return booleanQuery;
            }
            if (list.Count == 1)
            {
                return TermQuery(key.Invoke(list[0]), value.Invoke(list[0]));
            }
            return null;
        }

        public Query JoinQueries(Query left, Query right)
        {
            //return left.QueryAnd(right);
            if (left == null && right == null)
                return null;
            if (right != null && left != null)
            {
                var boolenQuery = new BooleanQuery();
                boolenQuery.Add(left, BooleanClause.Occur.MUST);
                boolenQuery.Add(right, BooleanClause.Occur.MUST);
                return boolenQuery;
            }
            return right ?? left;
        }

        public Query TermQuery(string key, string value)
        {
            return new TermQuery(new Term(key, value));
        }

        public T Where(string property, string value)
        {
            if (!string.IsNullOrEmpty(property))
            {
                Query = JoinQueries(Query, TermQuery(property, value));
            }
            return this as T;
        }

        public IEnumerable<Document> Results(SearchManager searchManager)
        {
            EnsureQuery();
            int total;
            return searchManager.Search(IndexType, Query, null, null, 0, Globals.INDEX_READER_MAX, out total);
        }

        public IEnumerable<Document> Results()
        {
            return Results(new SearchManager());
        }

        public abstract LuceneIndexType IndexType { get; }
    }
}
